package com.gps.track;

import java.util.ArrayList;
import java.util.Calendar;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.location.GpsStatus;
import android.location.GpsStatus.Listener;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.widget.Chronometer;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.appengine.utils.AeLoadingCenter;
import com.appengine.utils.GsonUtils;
import com.appengine.utils.SavingAndLoadingCenter;
import com.appengine.utils.UIUtils;
import com.appengine.utils.UserUtils;
import com.datatypes.Activity;
import com.datatypes.ActivityTracks;
import com.datatypes.Friend;
import com.datatypes.FriendsZone;
import com.datatypes.GeoPtr;
import com.datatypes.Log;
import com.datatypes.OfflineLogs;
import com.datatypes.Settings;
import com.datatypes.Track;
import com.datatypes.User;
import com.datatypes.UserTracks;
import com.facebook.android.Facebook;
import com.facebook.android.FacebookUtils;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.gps.utilities.CalorieCalculator;
import com.gps.utilities.TTS;
import com.gps.utilities.distanceCalculate;
import com.sporteamws.MainMenu;
import com.sporteamws.R;
import com.sporteamws.SharedPref;

public class GpsTrackingActivitySolo extends MapActivity implements
		LocationListener {

	MapView map;
	Chronometer timer;
	TextView speed;
	TextView distance;
	TextView calories;
	ImageView signal;
	ImageButton button;

	ArrayList<GeoPtr> myPoints = null;
	Track track = null;

	MapController contorller;
	LocationManager lm;
	Location myLocation = null;

	boolean activityRun = false;
	boolean start = true;
	boolean finish = false;
	boolean gpsFix = false;

	private boolean speak = false;
	private boolean save = false;
	private boolean post = true;

	DrawPathOverlay drawPathMy = null;

	distanceCalculate calc;
	CalorieCalculator calca;

	long lastTime = 0;
	long timeStamp = 0;
	long deltaTime = 0;
	double myCalories = 0;
	double mySpeed = 0;
	double accSpeed = 0;

	private float minSpeed = 1;
	private float MinDistance = 3;

	User user = null;
	Handler setUi = null;
	Runnable run = null;
	Runnable ttsMy = null;

	TTS tts = null;

	@Override
	protected boolean isRouteDisplayed() {
		return true;
	}

	@Override
	protected void onCreate(Bundle icicle) {
		super.onCreate(icicle);

		/** set layout **/
		setContentView(R.layout.runningscreanteam);
		map = (MapView) findViewById(R.id.mvMain);
		speed = (TextView) findViewById(R.id.speed);
		distance = (TextView) findViewById(R.id.distance);
		signal = (ImageView) findViewById(R.id.gps_signal);
		timer = (Chronometer) findViewById(R.id.timer);
		button = (ImageButton) findViewById(R.id.activityButton);
		calories = (TextView) findViewById(R.id.calories);
		/****************/
		if(SharedPref.screenOn)
			getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

		map.setBuiltInZoomControls(true);
		contorller = map.getController();
		contorller.setZoom(18);
		/************************************/

		/***********************************/
		user = GsonUtils.ConvertGsonStringToUser(getIntent().getExtras()
				.getString("USER"));
		activityRun = !getIntent().getExtras().getBoolean("SOLO");

		calc = new distanceCalculate();

		calca = new CalorieCalculator(user);

		myPoints = new ArrayList<GeoPtr>();
		drawPathMy = new DrawPathOverlay(myPoints, false, true, false,
				contorller, SharedPref.myTrackColor);

		if (SharedPref.ttsOn) {
			tts = new TTS(this);
			initMyTTS();
		}
		setUi = new Handler();
		map.getOverlays().add(drawPathMy);
		
		/** placing my location getting the location of the device **/
		lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
		/** check if needed **/
		lm.addGpsStatusListener(new Listener() {

			boolean lostConnection = false;

			public void onGpsStatusChanged(int event) {
				if (event == GpsStatus.GPS_EVENT_FIRST_FIX && !gpsFix) {
					gpsFix = true;
					UIUtils.PrintToast(GpsTrackingActivitySolo.this,
							"the GPS fixed your location", Toast.LENGTH_LONG);
					if (gpsFix && myLocation != null)
						contorller.animateTo(new GeoPoint((int) (myLocation
								.getLatitude() * 1E6), (int) (myLocation
								.getLongitude() * 1E6)));
					if (tts != null && SharedPref.ttsGpsStatus)
						tts.gpsSignal(true);
				}

				if (event == GpsStatus.GPS_EVENT_SATELLITE_STATUS) {
					if (myLocation != null) {
						if ((SystemClock.elapsedRealtime() - lastTime) > 25000
								&& !lostConnection) {
							setUi.post(new Runnable() {
								public void run() {
									getStrength(0);
								}
							});
							if (tts != null && SharedPref.ttsGpsStatus)
								tts.gpsSignal(false);
							lostConnection = true;
						} else if ((SystemClock.elapsedRealtime() - lastTime) < 25000
								&& lostConnection) {
							lostConnection = false;
							if (tts != null && SharedPref.ttsGpsStatus)
								tts.gpsSignal(true);
						}
					}

				}

			}
		});

		lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 5,
				GpsTrackingActivitySolo.this);
		button.setOnClickListener(new OnClickListener() {

			public void onClick(View v) {
				if (start && gpsFix) {
					button.setImageResource(R.drawable.stop_v2);

					/************/
					timeStamp = myLocation.getTime();
					GeoPtr gpt = new GeoPtr(myLocation.getLatitude(),
							myLocation.getLongitude(),
							(myLocation.getTime() - timeStamp), myLocation
									.getSpeed(), myLocation.getAltitude());
					myPoints.add(gpt);
					calc.setLast(myLocation);
					calca.setAlt(gpt.getAltitude());
					/************/

					start = false;
					timer.setBase(SystemClock.elapsedRealtime());
					timer.start();
					updateBoard();

					if (tts != null) {
						Thread ttsMyT = new Thread(ttsMy);
						ttsMyT.start();
					}

				} else if (start) {
					UIUtils.PrintToast(GpsTrackingActivitySolo.this,
							"no GPS signal, please wait", Toast.LENGTH_LONG);
				} else {
					timer.stop();
					lm.removeUpdates(GpsTrackingActivitySolo.this);
					if (tts != null)
						tts.shutDown();
					drawPathMy.stop = true;

					if (!myPoints.isEmpty()) {
						button.setVisibility(View.INVISIBLE);
						button.setOnClickListener(null);
						track = addData();
						ghostStatistics(track, false);
						if (activityRun)
							trackHandeling();

						finish = true;
					} else
						finish();
				}
			}

		});
	}

	@Override
	protected void onPause() {
		super.onPause();

	}

	@Override
	protected void onResume() {
		super.onResume();
	}

	public void onLocationChanged(Location location) {
		lastTime = SystemClock.elapsedRealtime();
		Location l = fireWall(location, myLocation);
		if (l == null && myLocation == null)
			myLocation = location;
		else if (l != null)
			myLocation = l;
		if (!start && (l != null)) {
			GeoPtr gpt = new GeoPtr(l.getLatitude(), l.getLongitude(),
					(l.getTime() - timeStamp), l.getSpeed(), l.getAltitude());
			calc.getDistance(l);
			myPoints.add(gpt);
			gpt.setCalories(calca.UpdateCaloriesBurned(gpt));
			myCalories += gpt.getCalories();
			mySpeed = gpt.GetSpeed();
			accSpeed += mySpeed;
			updateBoard();
		}
		getStrength(location.getAccuracy());
	}

	public void onProviderDisabled(String provider) {
		// TODO Auto-generated method stub

	}

	public void onProviderEnabled(String provider) {
		// TODO Auto-generated method stub

	}

	public void onStatusChanged(String provider, int status, Bundle extras) {
		// TODO Auto-generated method stub

		if (status == LocationProvider.AVAILABLE && !gpsFix) {

		}
		// Toast.makeText(this, "the GPS is now available",
		// Toast.LENGTH_LONG).show();
		else if (status == LocationProvider.TEMPORARILY_UNAVAILABLE) {
			getStrength(0);
		}
		// Toast.makeText(this, "the GPS is unavilable",
		// Toast.LENGTH_LONG).show();

	}

	@Override
	public void onBackPressed() {
		if (finish)
			if (!save)
				showDialog(1);
			else {
				super.onBackPressed();
				finish();
			}
		else if (!start) {
		} else {
			super.onBackPressed();
			if (tts != null)
				tts.shutDown();
			lm.removeUpdates(GpsTrackingActivitySolo.this);
			if (activityRun)
				SharedPref.returnToMainMenu = false;
			finish();

		}
	}

	@Override
	public boolean onPrepareOptionsMenu(Menu menu) {
		menu.clear();
		if (finish) {
			menu.add("continue").setIcon(android.R.drawable.ic_menu_revert);
			menu.add("post").setIcon(R.drawable.facebook_icon_post);
			menu.add("Save track").setIcon(android.R.drawable.ic_menu_save);
		} else if (start) {
			menu.add("My locaton").setIcon(
					android.R.drawable.ic_menu_mylocation);
		}
		return super.onPrepareOptionsMenu(menu);
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {

		String title = item.getTitle().toString();

		if (title.equals("continue")) {
			if (tts != null)
				tts.shutDown();
			if (!save)
				showDialog(1);
			else
				finish();
		} else if (title.equals("My locaton")) {
			if (gpsFix && myLocation != null)
				contorller.animateTo(new GeoPoint((int) (myLocation
						.getLatitude() * 1E6),
						(int) (myLocation.getLongitude() * 1E6)));
			else
				UIUtils.PrintToast(GpsTrackingActivitySolo.this, "no GPS signal, please wait",
						Toast.LENGTH_LONG);
		} else if (title.equals("Save track")) {
			if (!save)
				showDialog(0);
		} else if (title.equals("post")) {
			if (post) {
				track.setSynced(true);
				if (save) {
					UserTracks ut = SavingAndLoadingCenter.loadUserTracks(
							user.GetFacebookID(), this);
					ut.getTrack(track.getDate()).setSynced(true);
					SavingAndLoadingCenter.saveUserTracks(user.GetFacebookID(),
							ut, this);
				}
				map.setDrawingCacheEnabled(true);
				AeLoadingCenter.PostTracWithImgkOnFB(new Facebook(
						SharedPref.facebook_appID), track, map
						.getDrawingCache(), this);
				post = false;
			}
		}

		return super.onOptionsItemSelected(item);
	}

	protected Dialog onCreateDialog(int id) {
		Builder builder = null;

		if (id == 0) {
			builder = new Builder(this);
			builder.setTitle("save track");
			builder.setIcon(android.R.drawable.ic_menu_save);

			final EditText newName = new EditText(this);
			newName.setText(track.getName());
			builder.setView(newName);
			builder.setNegativeButton("cancel", null);
			builder.setPositiveButton("OK",
					new DialogInterface.OnClickListener() {

						public void onClick(DialogInterface arg0, int arg1) {
							track.setName(newName.getText().toString());
							UserTracks userTracks = SavingAndLoadingCenter
									.loadUserTracks(user.GetFacebookID(),
											GpsTrackingActivitySolo.this);
							userTracks.addTrack(track, user);
							AeLoadingCenter.SendTrack(track,
									user.GetFacebookID(),
									GpsTrackingActivitySolo.this);
							SavingAndLoadingCenter.saveUserTracks(
									user.GetFacebookID(), userTracks,
									GpsTrackingActivitySolo.this);
							save = true;
						}
					});
			AlertDialog dialog = builder.create();
			return dialog;
		} else if (id == 1) {
			builder = new Builder(this);
			builder.setTitle("exit & save");
			builder.setIcon(android.R.drawable.ic_popup_reminder);
			builder.setNegativeButton("no",
					new DialogInterface.OnClickListener() {

						@Override
						public void onClick(DialogInterface arg0, int arg1) {
							save = true;
							onBackPressed();
						}
					});
			builder.setPositiveButton("yes",
					new DialogInterface.OnClickListener() {

						public void onClick(DialogInterface dialog, int which) {
							if (!save)
								showDialog(0);
						}

					});
			AlertDialog dialog = builder.create();
			dialog.setMessage("You didn't save the track, do you want to save?");
			return dialog;
		} else
			return null;
	}

	/* update the board */
	private void updateBoard() {
		calories.setText(String.format("%.02f", myCalories));
		distance.setText(calc.getDistancStr());
		speed.setText(String.format("%.02f", mySpeed));
	}

	private void ghostStatistics(Track track, boolean showTime) {
		distance.setText(String.format("%.02f",
				(track.getDistance() > 1000) ? (track.getDistance()) / 1000
						: track.getDistance()));
		speed.setText(String.format("%.02f", track.GetAvgSpeed()));
		calories.setText(String.format("%.02f", track.GetCalories()));
		if (showTime)
			timer.setBase(SystemClock.elapsedRealtime() - track.getTime());
	}

	private Track addData() {
		return new Track(accSpeed / myPoints.size(), calc.getTotalDistance(),
				myCalories, myPoints.get(myPoints.size() - 1).getMS(), myPoints);
	}

	private void getStrength(float accuracy) {
		if (accuracy == 0)
			signal.setImageResource(R.drawable.gps_signal_0);
		else if (accuracy < 10)
			signal.setImageResource(R.drawable.gps_signal_4);
		else if (accuracy < 50)
			signal.setImageResource(R.drawable.gps_signal_3);
		else if (accuracy < 80)
			signal.setImageResource(R.drawable.gps_signal_2);
		else
			signal.setImageResource(R.drawable.gps_signal_1);
	}

	private Location fireWall(Location newLoc, Location last) {

		if (last == null)
			return newLoc;

		if (newLoc.getTime() <= last.getTime())
			return null;
		if (newLoc.getTime() < 0)
			return null;

		float distance = newLoc.distanceTo(last);
		float speed1 = (float) (3.6 * distance / ((newLoc.getTime() - last
				.getTime()) / 1000));
		float speed2 = (float) (newLoc.getSpeed() * 3.6);

		if (distance < MinDistance && speed1 < minSpeed)
			return newLoc;
		else if (distance < MinDistance && speed1 > minSpeed)
			return null;
		else if (distance > MinDistance)
			return newLoc;

		return null;
	}

	private void initMyTTS() {
		ttsMy = new Runnable() {
			public void run() {
				int time = 0;
				int deley = 0;
				long timerBase = timer.getBase();

				try {
					Thread.sleep(SharedPref.ttsMyDeley * 1000);
				} catch (InterruptedException e1) {
					e1.printStackTrace();
				}

				while (!finish) {
					setSpeak(true);
					time = SharedPref.ttsMyDeley - deley * 20;
					if (time <= 0)
						time = SharedPref.ttsMyDeley;
					deley = 0;
					tts.runningStatus("" + (int) accSpeed / myPoints.size(),
							calc.getTotalDistance(), "" + (int) myCalories,
							SystemClock.elapsedRealtime() - timerBase, false);
					try {
						Thread.sleep(time * 1000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		};
	}

	private void trackHandeling() {
		FriendsZone fz = SavingAndLoadingCenter.loadFriendsZone(
				user.GetFacebookID(), this);
		Friend friend = fz.getFriend(getIntent().getExtras()
				.getString("FRIEND"));

		ActivityTracks activityTracks = SavingAndLoadingCenter
				.loadActivityTracks(user.GetFacebookID(), this);
		Activity activity = new Activity(track, user.GetFacebookID(),
				friend.getFbID(), user.GetFirstName() + " "
						+ user.GetLastName(), friend.getName());
		/*
		 * boolean isSend = UserUtils.SendActivityToUser(activity);
		 * 
		 * if (!isSend) { OfflineLogs oll =
		 * SavingAndLoadingCenter.loadOfflineLogs( user.GetFacebookID(), this);
		 * oll.addLog(new Log(activity.getActivity_id(), true));
		 * SavingAndLoadingCenter.saveOfflineLogs(user.getFacebook_code(), oll,
		 * this); }
		 */
		AeLoadingCenter.SendActivity(activity, this);
		activityTracks.addActivity(activity, user);
		SavingAndLoadingCenter.saveActivityTracks(user.GetFacebookID(),
				activityTracks, this);

		friend.setInActivity(true);
		SavingAndLoadingCenter.saveFriendsZone(user.GetFacebookID(), fz, this);

	}

	public boolean isSpeak() {
		return speak;
	}

	public void setSpeak(boolean speak) {
		this.speak = speak;
	}
}
